<?php
class system_controller_front {
	
	public function __construct() {
	
	}
	
	protected $_baseUrl = null;
	public function setBaseUrl($base = null) {
		if(!is_string($base) && (null !== $base)) {
			throw new system_exception('Rewrite base must be a string');
		}		
		$this->_baseUrl = $base;		
		if((null !== ($request = $this->getRequest())) && (method_exists($request, 'setBaseUrl'))) {
			$request->setBaseUrl($base);
		}		
		return $this;
	}
	
	public function getBaseUrl() {
		$request = $this->getRequest();
		if((null !== $request) && method_exists($request, 'getBaseUrl')) {
			return $request->getBaseUrl();
		}
		return $this->_baseUrl;
	}
	
	static $_instance = null;
	/**
	 * @return system_controller_front
	 */
	public static function getInstance() {
		if(null === self::$_instance) {
			self::$_instance = new self();
		}		
		return self::$_instance;
	}
	
	protected $_throwExceptions = true;
	public function throwExceptions($flag = null) {
		if($flag !== null) {
			$this->_throwExceptions = (bool) $flag;
			return $this;
		}		
		return $this->_throwExceptions;
	}
	
	public function getControllerDirectory() {
		return $this->getDispatcher()->getControllerDirectory();
	}
	public function setControllerDirectory($directory) {
		$this->getDispatcher()->setControllerDirectory($directory);
		return $this;
	}
	
	protected $_request = null;
	/**
	 * @return system_controller_request_http
	 */
	public function getRequest() {
		if(null === $this->_request) {
			require_once 'request/http.php';
			$this->setRequest(new system_controller_request_http());
		}
		return $this->_request;
	}
	public function setRequest($request) {
		$this->_request = $request;
		return $this;
	}
	protected $_resposne = null;
	public function getResponse() {
		if(null === $this->_resposne) {
			require_once 'response/http.php';
			$this->setResponse(new system_controller_response_http());
		}
		return $this->_resposne;
	}
	public function setResponse($response) {
		$this->_resposne = $response;
		return $this;
	}
	
	protected $_router = null;
	/**
	 * @return system_controller_router
	 */
	public function getRouter() {
		if(null === $this->_router) {
			require_once 'router.php';
			$this->setRouter(new system_controller_router());
		}
		return $this->_router;
	}
	public function setRouter($router) {
		$this->_router = $router;
		return $this;
	}
	public function startRouter($configFile) {
		if(null === $this->_router) {
			$router = $this->getRouter();
			$config = include $configFile;
			foreach((array) $config as $key => $value) {
				isset($value['map']) ? '' : $value['map'] = array();
				isset($value['ssl']) ? $ssl = $value['ssl'] : $ssl = null;
				$router->addRoute($key, new system_controller_router_route($value['route'], $value['reverse'], $value['defaults'], $value['map'], $ssl));
			}
		}
	}
	
	protected $_dispatcher = null;
	/**
	 * @return system_controller_dispatcher
	 */
	public function getDispatcher() {
		if(null === $this->_dispatcher) {
			$dispatcher = new system_controller_dispatcher();
			$this->setDispatcher($dispatcher);
			unset($dispatcher);
		}
		return $this->_dispatcher;
	}
	public function setDispatcher($dispatcher) {
		$this->_dispatcher = $dispatcher;
		return $this;
	}
	
	public function dispatch() {
		$request = $this->getRequest();
		$request->setBaseUrl($this->getBaseUrl());		
		$response = $this->getResponse();		
		$router = $this->getRouter();		
		$dispatcher = $this->getDispatcher(); //分发器	
		try {			
			$router->route($request);		
		} catch (system_exception $e) {
			if($this->throwExceptions()) {
				throw $e;
			}
			$response->setException($e);
			$request->setControllerName('index')->setActionName('error');
		}
		try {
			do {				
				$request->setDispatched(true);
				$dispatcher->dispatch($request, $response);			
			} while(!$this->getRequest()->isDispatched());		
		} catch (system_exception $e) {
			if($this->throwExceptions()) {
				throw $e;
			}
			$response->setException($e);
			$request->setControllerName('index')->setActionName('error');
			$dispatcher->dispatch($request, $response);
		}
		return $response->sendResponse();
	}
}